/*  
 *  Copyright (c) 2008 Adrian Necimal <necimal@gmail.com>
 *  
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *  
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *  
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;

Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://app/jsmodules/sbProperties.jsm");
Cu.import("resource://app/jsmodules/sbLibraryUtils.jsm");

var gUnescapeHTML = Cc["@mozilla.org/feed-unescapehtml;1"].getService(Ci.nsIScriptableUnescapeHTML);
var gXPath = Cc["@mozilla.org/dom/xpath-evaluator;1"].createInstance(Ci.nsIDOMXPathEvaluator);

function SongbirdRecommendations() {
  this.wrappedJSObject = this;
};

SongbirdRecommendations.prototype = {
  classDescription: "Songbird Recommendations Javascript XPCOM Component",
  classID: Components.ID("{DB48C84A-0A92-40e3-8ACC-C21CC6D2D873}"),
  contractID: "@necimal.com/recommendations;1",
  QueryInterface: XPCOMUtils.generateQI([])
}

/*
 * Transform last.fm info on an artist info XUL using nifty XSLT
 */
SongbirdRecommendations.prototype.getArtistDOM = function(artistName) {
  // check the last artist queried cache
  if (this._recentArtistName == artistName) {
    return this._recentArtistDOM;
  }
  
  if (!this._xslt) {
    // create an XSLT processor, and initialise it with our xsl file
    var xslfile = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].createInstance(Ci.nsIXMLHttpRequest);
    xslfile.open("GET", "chrome://music-recommendations/content/artistinfo.xsl", false);
    xslfile.send(null);
    this._xslt = Cc["@mozilla.org/document-transformer;1?type=xslt"].createInstance(Ci.nsIXSLTProcessor);
    this._xslt.importStylesheet(xslfile.responseXML);
  }
  
  // make a request to Last.fm
  var requestUri = "http://ws.audioscrobbler.com/2.0/artist/info.xml?artist=" + escape(artistName);
  var request = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].createInstance(Ci.nsIXMLHttpRequest);
  request.open("GET", requestUri, false);
  try {
    request.send(null);
  }
  catch (e) { return null; } // no network connection
  if (!request.responseXML) { return null; } // no valid response (bad artist name?)
  
  // remove html from biography
  var bioNode = gXPath.evaluate("/artist/bio/summary", request.responseXML, null, 8, null).singleNodeValue;
  bioNode.textContent = gUnescapeHTML.unescape(bioNode.textContent);
  
  // add track counts
  try {
    var similarArtistNodes = gXPath.evaluate("/artist/similar/artist", request.responseXML, null, 6, null);
    for (i = 0; i < similarArtistNodes.snapshotLength; i++) {
      var similarArtist = similarArtistNodes.snapshotItem(i);
      var similarArtistName = similarArtist.getElementsByTagName("name").item(0).textContent;
      var simArtistCounter = new EnumerationCountListener();
      LibraryUtils.mainLibrary.enumerateItemsByProperty(SBProperties.artistName,
                                                        similarArtistName,
                                                        simArtistCounter);
      similarArtist.setAttribute('count', simArtistCounter.count);
    }
  } catch (e) {
    Cu.reportError(e);
  }
  
  // transform to XUL
  try {
    var doc = Cc["@mozilla.org/xul/xul-document;1"].createInstance(Ci.nsIDOMDocument);
    var result = this._xslt.transformToFragment(request.responseXML, doc).firstChild;
  } catch (e) {
    Cu.reportError(e);
  }
  
  // cache for later, and return
  this._recentArtistName = artistName;
  this._recentArtistDOM = result;
  return result;
}

/*
 * Counts the entries in an enumeration (used for counting tracks by an artist).
 */
function EnumerationCountListener() { }
EnumerationCountListener.prototype = {
  count: 0,
  onEnumerationBegin: function(aMediaList) {
    this.count = 0;
  },
  onEnumeratedItem: function(aMediaList, aMediaItem) {
    this.count++;
  },
  onEnumerationEnd: function(aMediaList, aStatusCode) { }
}

function NSGetModule(compMgr, fileSpec) {
  return XPCOMUtils.generateModule([SongbirdRecommendations]);
}
